/*
 * Customer.h
 *
 *  Created on: Jun 22, 2013
 *      Author: amatzlia
 */

#ifndef CUSTOMER_H_
#define CUSTOMER_H_

#include "Order.h"
#include <set>
#include <iostream>
using std::set;
using std::string;

/**
 * A class used to represent a customer in a record store, holding it's id,
 * name, and details about the orders that were made in the store (paid or not).
 */
class Customer {
public:
	/**
	 * Creates a new customer with given id and name.
	 * If given id is <= 0 then mtm::INVALID_ID exception is thrown.
	 */
	Customer(int id, const string& name);

	/**
	 * Creates a new customer with given id and empty name.
	 * For use as a search dummy object.
	 * If given id is <= 0 then mtm::INVALID_ID exception is thrown.
	 */
	explicit Customer(int id);

	/**
	 * Creates a new customer from an existing one.
	 * @param customer the customer to copy.
	 */
	Customer(const Customer& customer);

	~Customer();
	Customer& operator=(const Customer& customer);

	/**
	 * @return a string describing the customer, its orders,
	 * and the albums in each of the orders.
	 * The orders are sorted by id, and the albums in each order are sorted by
	 * time of addition to the order.
	 */
	string getReportString() const;

	/**
	 * @return a string representing a minimal description of the customer.
	 */
	string getDescriptionString() const;

	/**
	 * @return a string representing the customer's revenue details.
	 */
	string getRevenueString() const;

	/**
	 * Creates a new open order for the customer.
	 * If the customer already has an open order,
	 * mtm::CUSTOMER_HAS_OPEN_ORDER exception is thrown.
	 * @param orderId The id of the new order.
	 */
	void createNewOrder(int orderId);

	/**
	 * Adds an album to the customer's open order.
	 * If the given orderId is not the id of the customer's current open order,
	 * or the customer doesn't have an open order, we assume that orderId is of
	 * an already paid order and mtm::ORDER_WAS_ALREADY_PAID exception is thrown.
	 * @param orderId the id of the order to add the album to.
	 * @param album the album to add to the open order.
	 */
	void addToOpenOrder(int orderId, const Album& album);

	/**
	 * Removes an album/albums from the customer's open order.
	 * If the given orderId is not the id of the customer's current open order,
	 * or the customer doesn't have an open order, we assume that orderId is of
	 * an already paid order and mtm::ORDER_WAS_ALREADY_PAID exception is thrown.
	 * If no matching album is found in the open order,
	 * mtm::ORDER_DOESNT_HAVE_ALBUM exception is thrown.
	 * @param orderId the id of the order to remove the album/albums to.
	 * @param album the album to remove from the open order.
	 */
	void removeFromOpenOrder(int orderId, const Album& album);

	/**
	 * Pays for the customer's open order.
	 * If the given orderId is not the id of the customer's current open order,
	 * or the customer doesn't have an open order, we assume that orderId is of
	 * an already paid order and mtm::ORDER_WAS_ALREADY_PAID exception is thrown.
	 * If the open order is empty, mtm::ORDER_IS_EMPTY exception is thrown.
	 * The order status is changed to paid, and the customer then owns the
	 * albums in the order.
	 * @param orderId the id of the open order to pay for.
	 * @return a list of the albums that were just bought by the customer.
	 */
	List<Album> payForOpenOrder(int orderId);

	/**
	 * A function object used to sort Customer objects by id (ascending)
	 * and to find them by id, in a set of Customers.
	 */
	class SortById;

private:
	/**
	 * Verifies the given orderId is of the current open order of the customer.
	 * If the given orderId is not the id of the customer's current open order,
	 * or the customer doesn't have an open order, we assume that orderId is of
	 * an already paid order and mtm::ORDER_WAS_ALREADY_PAID exception is thrown.
	 * @param orderId the id of the order that should be the
	 *  customer's open order.
	 */
	void verifyOpenOrder(int orderId) const;

	/**
	 * Check if and order with the given order id was paid by the customer.
	 * @param orderId the id of the order that was paid.
	 * @return true if the order was paid by the customer, false otherwise.
	 */
	bool orderWasPaid(int orderId) const;

	int id;
	string name;
	int moneySpent;
	int albumsOwned;
	Order* openOrder;
	set<Order, Order::SortById> paidOrders;
};

class Customer::SortById {
public:
	bool operator()(const Customer& customerA, const Customer& customerB) const;
};
#endif /* CUSTOMER_H_ */
